/**
 * Copyright (C) <2023> <Boundivore> <boundivore@foxmail.com>
 * <p>
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the Apache License, Version 2.0
 * as published by the Apache Software Foundation.
 * <p>
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * Apache License, Version 2.0 for more details.
 * <p>
 * You should have received a copy of the Apache License, Version 2.0
 * along with this program; if not, you can obtain a copy at
 * http://www.apache.org/licenses/LICENSE-2.0.
 */
/**
 * 修改配置文件页面
 * @author Tracy
 */
import { useEffect, useState, useRef, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useSearchParams } from 'react-router-dom';
import { Tabs, Col, Row, Space, Button, message, App, Typography, Popover, Input, Card, Flex, Tooltip } from 'antd';
import { PlusCircleOutlined, QuestionCircleOutlined } from '@ant-design/icons';
import type { TabsProps } from 'antd';
import { Resizable } from 're-resizable';
import _ from 'lodash';
import CryptoJS from 'crypto-js';
import sha256 from 'crypto-js/sha256';
import Base64 from 'crypto-js/enc-base64';
import Utf8 from 'crypto-js/enc-utf8';
import RequestHttp from '@/api';
import APIConfig from '@/api/config';
import useStore from '@/store/store';
import useNavigater from '@/hooks/useNavigater';
import CodeEditor from './codeEditor';
import NodeListModal from './components/nodeListModal';
import { ConfigSummaryVo, ConfigGroupVo } from '@/api/interface';
import ContainerCard from '@/components/containerCard';
import { fuzzySearchFiles } from '@/utils/helper';

const { Paragraph } = Typography;
const { Search } = Input;
// 从 TabsProps 中提取 items 类型
type TabItem = NonNullable<TabsProps['items']>[number];

// 使用交叉类型将 ConfigSummaryVo 合并到 TabItem 中
type MergedTabItem = TabItem & ConfigSummaryVo;

// 定义扩展后的 TabsProps 类型
type MergedTabsProps = {
	items: MergedTabItem[];
};
const ModifyConfig: React.FC = () => {
	const { t } = useTranslation();
	const [searchParams] = useSearchParams();
	const id = searchParams.get('id');
	const serviceName = searchParams.get('name') || '';
	const [tabsData, setTabsData] = useState<MergedTabsProps['items']>([]);
	const [allTabsData, setAllTabsData] = useState<MergedTabsProps['items']>([]);
	const [activeTab, setActiveTab] = useState<string>('');
	const [activeContent, setActiveContent] = useState<ConfigGroupVo[]>([]);
	const [codeEdit, setCodeEdit] = useState<string>('');
	const [codeVersion, setCodeVersion] = useState<string>('');
	const [currentGroupIndex, setCurrentGroupIndex] = useState(0);
	const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
	const [configPath, setConfigPath] = useState<string>('');
	const [files, setFiles] = useState<string[]>([]);
	const { configGroupInfo, setConfigGroupInfo, setIsConfigModified, isConfigModified } = useStore();
	const [messageApi, contextHolder] = message.useMessage();
	const { navigateToService } = useNavigater();
	const { modal } = App.useApp();

	const editorRef = useRef<{ handleSave: () => string } | null>(null);
	// const textRef = useRef<(HTMLSpanElement | null)[]>([]);

	const getConfigFile = async () => {
		// setLoading(true);
		const api = APIConfig.listSummary;
		const params = { ClusterId: id, ServiceName: serviceName };
		const data = await RequestHttp.get(api, { params });
		const {
			Data: { ConfigSummaryList }
		} = data;
		let fileNames: string[] = [];
		const tabs = ConfigSummaryList.map((item: ConfigSummaryVo) => {
			fileNames.push(item.FileName);
			return {
				...item,
				key: item.ConfigPath,
				label: (
					<Popover
						placement="left"
						content={
							<Paragraph className="mb-0" copyable>
								{item.ConfigPath}
							</Paragraph>
						}
					>
						{item.FileName}
					</Popover>
				)
			};
		});
		setFiles(fileNames);
		// setLoading(false);
		setActiveTab(tabs[0].key); // 默认选中第一项
		setTabsData(tabs);
		setAllTabsData(tabs);
	};
	const getFileContent = async () => {
		// setLoading(true);
		const api = APIConfig.listByGroup;
		const { ConfigPath } = tabsData?.find(item => item.key === activeTab) ?? { ConfigPath: '' };
		const params = { ClusterId: id, ServiceName: serviceName, Filename: activeTab, ConfigPath };
		const data = await RequestHttp.get(api, { params });
		const {
			Data: { ConfigGroupList }
		} = data;
		// setLoading(false);
		// paramData = ConfigGroupList;
		const copyData = _.cloneDeep(ConfigGroupList);
		const codeData = Utf8.stringify(Base64.parse(copyData[0].ConfigData));
		setActiveContent(copyData);
		setCodeEdit(codeData);
		setCodeVersion(copyData[0].ConfigNodeList[0].ConfigVersion);
		setConfigGroupInfo(copyData);
		setConfigPath(ConfigPath);
	};

	useEffect(() => {
		setActiveContent(configGroupInfo);
	}, [configGroupInfo]);
	useEffect(() => {
		getConfigFile();
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, []);
	useEffect(() => {
		activeTab && getFileContent();
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [activeTab]);
	const handleClick = (index: number) => {
		if (isConfigModified) {
			processEditorData();
			setConfigGroupInfo(configGroupInfo);
		}

		setCurrentGroupIndex(index);
		setCodeEdit(Utf8.stringify(Base64.parse(activeContent[index].ConfigData)));
		setCodeVersion(activeContent[index].ConfigNodeList[0].ConfigVersion);
		setIsModalOpen(true);
	};
	const handleModalOk = useCallback((targetGroupIndex: number, data: ConfigGroupVo[]) => {
		// 新建分组，添加到其他分组
		setIsModalOpen(false);
		if (targetGroupIndex >= data.length) {
			setCurrentGroupIndex(data.length - 1);
		} else {
			setCurrentGroupIndex(targetGroupIndex);
		}
	}, []);
	const handleModalCancel = useCallback(() => {
		setIsModalOpen(false);
	}, []);
	const processEditorData = () => {
		const editorValue = editorRef.current?.handleSave() ?? '';
		const base64Data = btoa(unescape(encodeURIComponent(editorValue)));
		const hashDigest = sha256(editorValue).toString(CryptoJS.enc.Hex);

		_.merge(configGroupInfo[currentGroupIndex], {
			Sha256: hashDigest,
			ConfigData: base64Data
		});
	};
	const saveChange = async () => {
		const api = APIConfig.saveByGroup;
		processEditorData();
		const params = {
			ClusterId: id,
			ConfigGroupList: configGroupInfo,
			ServiceName: serviceName
		};
		const data = await RequestHttp.post(api, params);
		const { Code } = data;
		if (Code === '00000') {
			messageApi.success(t('messageSuccess'));
			setIsConfigModified(false);
			// navigateToService();
		}
	};

	const [width, setWidth] = useState(300);

	const handleSearch = (text: string) => {
		const result = fuzzySearchFiles(files, text);
		const filteredTabsData = allTabsData.filter(file => result.includes(file.FileName));
		setTabsData(filteredTabsData);
	};
	return (
		<ContainerCard>
			{contextHolder}
			<Flex gap="middle" className="w-[100%] overflow-hidden">
				<Resizable
					size={{ width, height: 'auto' }}
					onResizeStop={(_e, _direction, _ref, d) => {
						setWidth(width + d.width); // 更新宽度
					}}
					enable={{
						right: true // 只允许从右侧拖动
					}}
					minWidth={200}
					maxWidth={450}
				>
					<Card
						title={
							<div className="flex items-center">
								<img src={`/service_logo/${serviceName.toLowerCase()}.svg`} width="16" height="16" />
								<span className="pl-[5px]">{serviceName}</span>
							</div>
						}
						className="w-[100%]"
					>
						<Search
							placeholder={t('inputFileName')}
							allowClear
							className="mb-[20px] w-[100%]"
							onSearch={value => handleSearch(value)}
						/>
						<Tabs
							className="h-[550px]"
							tabBarStyle={{ width: '100%' }}
							tabPosition="left"
							items={tabsData}
							activeKey={activeTab}
							onChange={activeKey => {
								if (isConfigModified) {
									modal.confirm({
										title: t('warning'),
										content: t('warningText'),
										okText: t('confirm'),
										cancelText: t('cancel'),
										onOk: async () => {
											setActiveTab(activeKey);
											setIsConfigModified(false);
											setCurrentGroupIndex(0);
										}
									});
								} else {
									setActiveTab(activeKey);
									setCurrentGroupIndex(0);
								}
							}}
						/>
					</Card>
				</Resizable>
				<Row className="w-[100%] h-[100%] min-w-[1px]">
					<Col span={4}>
						<Card
							title={
								<Space>
									{t('setGroup')}
									<Tooltip title={t('groupPrompt')}>
										<QuestionCircleOutlined />
									</Tooltip>
								</Space>
							}
							bordered={true}
							className="h-[100%] overflow-y-auto max-h-[690px] min-w-[130px]"
						>
							<Space direction="vertical">
								{configGroupInfo.map((_group, index) => {
									return (
										<Space key={index}>
											<Button
												key={index}
												size="middle"
												type={index === currentGroupIndex ? 'primary' : 'default'}
												onClick={() => {
													if (isConfigModified) {
														processEditorData();
														setConfigGroupInfo(configGroupInfo);
													}

													setCurrentGroupIndex(index);
													setCodeEdit(Utf8.stringify(Base64.parse(activeContent[index].ConfigData)));
													setCodeVersion(activeContent[index].ConfigNodeList[0].ConfigVersion);
												}}
											>
												{t('group', { name: index + 1 })}
											</Button>
											<PlusCircleOutlined style={{ fontSize: '16px' }} onClick={() => handleClick(index)} />
										</Space>
									);
								})}
							</Space>
						</Card>
					</Col>
					<Col className="min-h-[500px]" span={20}>
						<Card
							title={
								<Flex vertical={true}>
									<Space className="pt-[15px] pb-[10px]">
										<Paragraph className="mb-0 text-[16px]" copyable>
											{configPath}
										</Paragraph>
										<span>
											{t('version')}
											{codeVersion}
										</span>
									</Space>
									<Space className="pb-[10px]">
										<Button type="primary" onClick={saveChange}>
											{t('save')}
										</Button>
										<Button onClick={navigateToService}>{t('back')}</Button>
									</Space>
								</Flex>
							}
						>
							<CodeEditor ref={editorRef} data={codeEdit} index={currentGroupIndex} />
						</Card>
					</Col>
				</Row>
			</Flex>

			{isModalOpen ? (
				<NodeListModal
					isModalOpen={isModalOpen}
					groupIndex={currentGroupIndex}
					handleOk={handleModalOk}
					handleCancel={handleModalCancel}
				/>
			) : null}
		</ContainerCard>
	);
};

export default ModifyConfig;
